using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using SBPweb.Localization;
using SBPweb.Modules.Modularity;
using SBPweb.Modules.Smartparts;
using SBPweb.Contracts;
using SBPweb.Contracts.Messaging;

using SBPweb.Presentation.Windows.Forms.Controls;
using SBPweb.Contracts.Implementation;
using System.Security.Cryptography;
using System.IO;
using SBPweb.Modules.Messaging.Controls;
using System.Text.RegularExpressions;

namespace SBPweb.Modules.Messaging
{
	public partial class LoginControl : UserControl
	{
		#region Private members

		private IModule mParentModule;
		private byte[] byKey = System.Text.Encoding.UTF8.GetBytes("&%#@?,:*");
		private byte[] IV = { 0x12, 0x34, 0x56, 0x78, 0x90, 0xAB, 0xCD, 0xEF };
		private Regex mUserName = new Regex("^[a-z0-9]([_a-z0-9.-])*[a-z0-9]$");
		private Regex mServer = new Regex("^[a-z0-9]([a-z0-9.-])*[a-z0-9]$");

		#endregion

		#region Public members

		public IModule ParentModule
		{
			get
			{
				return mParentModule;
			}
		}

		public IMessagingService DirectoryService
		{
			get
			{
				return mParentModule.Services.Get<IMessagingService>();
			}
		}

		internal string CurrentPassword
		{
			get
			{
				return tbPassword.Text;
			}
		}

		internal string CurrentUser
		{
			get
			{
				return tbUserName.Text;
			}
		}

		internal string DirectoryServer
		{
			get
			{
				return tbDirectory.Text;
			}
		}

		internal string ConferenceServer
		{
			get
			{
				return tbConference.Text;
			}
		}

		internal string PubsubServer
		{
			get
			{
				return tbPubsub.Text;
			}
		}

		internal int Port
		{
			get
			{
				int retVal;
				if (int.TryParse(tbPort.Text, out retVal))
				{
					return retVal;
				}
				return 0;
			}
		}

		internal bool IsSaveUserName
		{
			get
			{
				return cbxRememberUserName.Checked;
			}
		}

		internal bool IsSavePassword
		{
			get
			{
				return cbxRememberPassword.Checked;
			}
		}

		#endregion

		#region Constructor logic

		public LoginControl(IModule parentModule)
		{
			mParentModule = parentModule;

			InitializeComponent();

			this.Load += new EventHandler(LoginControl_Load);

			DirectoryService.OnAutenticate += new ConnectionHandler(DirectoryService_OnAutenticate);
			DirectoryService.OnAuthenticationError += new ConnectionHandler(DirectoryService_OnAuthenticationError);
			DirectoryService.OnDisconnect += new ConnectionHandler(DirectoryService_OnDisconnect);
            DirectoryService.OnError += new ConnectionErrorHandler(DirectoryService_OnError);
			//DirectoryService.OnWarning += new ConnectionErrorHandler(DirectoryService_OnWarning);
			(mParentModule as MessagingModule).OnWarning += new ConnectionErrorHandler(LoginControl_OnWarning);
		}

		#endregion

		#region Event handlers

		private void LoginControl_Load(object sender, EventArgs e)
		{
			tbDirectory.Text = DirectoryService.Server;
			tbConference.Text = DirectoryService.ConferenceServer;
			tbPubsub.Text = DirectoryService.PubsubServer;
			tbPort.Text = DirectoryService.Port.ToString();

			tbUserName.Text = string.Empty;
			tbPassword.Text = string.Empty;
			cbxRememberUserName.Checked = true;
			cbxRememberPassword.Checked = false;
			(mParentModule as MessagingModule).LoadPersistency();
			if (DirectoryService.IsConnected)
			{
				tbUserName.Text = DirectoryService.UserName;
				tbPassword.Text = string.Empty;
			}
			cbxRememberUserName_CheckedChanged(sender, EventArgs.Empty);

			tbUserName.Select();
		}

		private void DirectoryService_OnDisconnect(object sender)
		{
			btnLogin.Enabled = true;
			btnLogout.Enabled = false;
			gbLogin.Enabled = true;
			gbServer.Enabled = true;
			gbSettings.Enabled = true;
			llbChangePassword.Visible = btnLogout.Enabled;
		}

        private void DirectoryService_OnError(object sender, string message)
        {
            btnLogin.Enabled = true;
            btnLogout.Enabled = false;
            gbLogin.Enabled = true;
            gbServer.Enabled = true;
            gbSettings.Enabled = true;
			llbChangePassword.Visible = btnLogout.Enabled;
			SBPweb.Controls.Windows.Common.MessageBox.Show(message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

		private void DirectoryService_OnAuthenticationError(object sender)
		{
			btnLogin.Enabled = true;
			btnLogout.Enabled = false;
			gbLogin.Enabled = true;
			gbServer.Enabled = true;
			gbSettings.Enabled = true;
			llbChangePassword.Visible = btnLogout.Enabled;
			SBPweb.Controls.Windows.Common.MessageBox.Show(LocalizationExtender.GetString("AuthenticationWrongUserNamePassword"), LocalizationExtender.GetString("AuthenticationWrongUserNamePasswordHeader"), MessageBoxButtons.OK, MessageBoxIcon.Information);
		}

		private void DirectoryService_OnAutenticate(object sender)
		{
			tbUserName.Text = DirectoryService.UserName;
			btnLogin.Enabled = false;
			btnLogout.Enabled = true;
			gbLogin.Enabled = false;
			gbServer.Enabled = false;
			gbSettings.Enabled = false;
			llbChangePassword.Visible = btnLogout.Enabled;
		}

		//private void DirectoryService_OnWarning(object sender, string message)
		//{
		//    SBPweb.Controls.Windows.Common.MessageBox.Show(string.Format(LocalizationExtender.GetString("DirectoryServerWarning"), message), "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
		//}

		private void LoginControl_OnWarning(object sender, string message)
		{
			SBPweb.Controls.Windows.Common.MessageBox.Show(string.Format(LocalizationExtender.GetString("DirectoryServerWarning"), message), "Warning!", MessageBoxButtons.OK, MessageBoxIcon.Warning);
		}

		private void cbxRememberUserName_CheckedChanged(object sender, EventArgs e)
		{
			cbxRememberPassword.Enabled = cbxRememberUserName.Checked;
		}

		private void btnLogin_Click(object sender, EventArgs e)
		{
			errorProvider.SetError(tbUserName, string.Empty);
			errorProvider.SetError(tbDirectory, string.Empty);
			errorProvider.SetError(tbConference, string.Empty);
			errorProvider.SetError(tbPubsub, string.Empty);
			errorProvider.SetError(tbPort, string.Empty);

			if (string.IsNullOrEmpty(tbUserName.Text))
			{
				MessageBox.Show(LocalizationExtender.GetString("EmptyUserName"), LocalizationExtender.GetString("EmptyUserNameHeader"), MessageBoxButtons.OK, MessageBoxIcon.Information);
				return;
			}
			if (!mUserName.IsMatch(tbUserName.Text))
			{
				errorProvider.SetError(tbUserName, LocalizationExtender.GetString("WrongValue"));
				return;
			}
			if (!mServer.IsMatch(tbDirectory.Text))
			{
				errorProvider.SetError(tbDirectory, LocalizationExtender.GetString("WrongValue"));
				return;
			}
			if (!mServer.IsMatch(tbConference.Text))
			{
				errorProvider.SetError(tbConference, LocalizationExtender.GetString("WrongValue"));
				return;
			}
			if (!mServer.IsMatch(tbPubsub.Text))
			{
				errorProvider.SetError(tbPubsub, LocalizationExtender.GetString("WrongValue"));
				return;
			}
			int portNumber = 0;
			{
				if (int.TryParse(tbPort.Text, out portNumber))
				{
					if (portNumber < 1025 || portNumber > 65000)
					{
						errorProvider.SetError(tbPort, LocalizationExtender.GetString("WrongValue"));
						return;
					}
				}
				else
				{
					errorProvider.SetError(tbPort, LocalizationExtender.GetString("WrongValue"));
					return;
				}
			}

			if (mParentModule.Host.ModuleLoader.IsAllModuleLoaded)
			{
				btnLogin.Enabled = false;
				btnLogout.Enabled = false;
				gbLogin.Enabled = false;
				gbServer.Enabled = false;
				gbSettings.Enabled = false;
				llbChangePassword.Visible = btnLogout.Enabled;

				if (!DirectoryService.IsConnected)
				{
					try
					{
						DirectoryService.Server = tbDirectory.Text;
						DirectoryService.ConferenceServer = tbConference.Text;
						DirectoryService.PubsubServer = tbPubsub.Text;
						int port = 0;
						if (!int.TryParse(tbPort.Text, out port))
						{
							port = 5222;
						}
						DirectoryService.Port = port;
					}
					catch (Exception ex)
					{
						mParentModule.Host.LogManager.WriteError(this, "Error during logging in: " + ex.Message, "DirectoryService");
					}
					try
					{
						DirectoryService.Connect(tbUserName.Text, tbPassword.Text);
					}
					catch (Exception ex)
					{
						mParentModule.Host.LogManager.WriteError(this, "Error during connectiong to the directory server: " + ex.ToString(), "DirectoryService");
						MessageBox.Show(string.Format(LocalizationExtender.GetString("ErrorDuringConnecting"), ex.ToString()), LocalizationExtender.GetString("CannotConnectAtConnectedStateHeader"), MessageBoxButtons.OK, MessageBoxIcon.Information);
						DirectoryService_OnDisconnect(this);
					}
				}
				else
				{
					MessageBox.Show(LocalizationExtender.GetString("CannotConnectAtConnectedState"), LocalizationExtender.GetString("CannotConnectAtConnectedStateHeader"), MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
			}

			(mParentModule as MessagingModule).SavePersistency();
		}

		private void btnLogout_Click(object sender, EventArgs e)
		{
			btnLogin.Enabled = false;
			btnLogout.Enabled = false;
			gbLogin.Enabled = false;
			gbServer.Enabled = false;
			gbSettings.Enabled = false;
			llbChangePassword.Visible = btnLogout.Enabled;

			if (mParentModule.Host.ModuleLoader.IsAllModuleLoaded)
			{
				if (DirectoryService.IsConnected)
				{
					DirectoryService.Disconnect();
				}
				else
				{
					MessageBox.Show(LocalizationExtender.GetString("CannotDisctonnectAtDisconnectedState"), LocalizationExtender.GetString("CannotDisctonnectAtDisconnectedStateHeader"), MessageBoxButtons.OK, MessageBoxIcon.Information);
				}
			}

			(mParentModule as MessagingModule).SavePersistency();
		}

		private void tbUserNameOrPassword_KeyDown(object sender, KeyEventArgs e)
		{
			if (e.KeyCode == Keys.Return)
			{
				btnLogin_Click(this, EventArgs.Empty);
			}
		}

		ChangePasswordControl cpc;
		private void llbChangePassword_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			if (cpc != null)
			{
				return;
			}
			cpc = new ChangePasswordControl(this);
			cpc.OnClosed += new EventHandler(cpc_OnClosed);
			mParentModule.Host.Smartparts.Add(cpc);
		}

		private void cpc_OnClosed(object sender, EventArgs e)
		{
			cpc.OnClosed -= new EventHandler(cpc_OnClosed);
			mParentModule.Host.Smartparts.Remove(cpc);
			cpc.Dispose();
			cpc = null;
		}

		#endregion

		#region Presitence handling

		public void SavePersistence(PersistencyDictionary state)
		{
			state.SetString("Directory", tbDirectory.Text);
			state.SetString("Conference", tbConference.Text);
			state.SetString("Pubsub", tbPubsub.Text);
			int port = 0;
			try
			{
				port = int.Parse(tbPort.Text);
			}
			catch (Exception) { }
			state.SetInt("Port", port);
			if (cbxRememberUserName.Checked)
			{
				state.SetString("UserName", tbUserName.Text);
				if (cbxRememberPassword.Checked)
				{
					state.SetString("Password", EncryptPassword(tbPassword.Text));
				}
			}
			state.SetBoolean("RememberUser", cbxRememberUserName.Checked);
			state.SetBoolean("RememberPassword", cbxRememberUserName.Checked && cbxRememberPassword.Checked);
		}

		public void LoadPersistence(PersistencyDictionary state)
		{
			tbDirectory.Text = state.GetString("Directory", tbDirectory.Text);
			tbConference.Text = state.GetString("Conference", tbConference.Text);
			tbPubsub.Text = state.GetString("Pubsub", tbPubsub.Text);
			int port = 0;
			try
			{
				port = int.Parse(tbPort.Text);
			}
			catch (Exception) { }
			tbPort.Text = state.GetInt("Port", port).ToString();
			tbUserName.Text = state.GetString("UserName", string.Empty);
			string pass = state.GetString("Password", string.Empty);
			tbPassword.Text = pass == string.Empty ? pass : DecryptPassword(pass);
			cbxRememberUserName.Checked = state.GetBoolean("RememberUser", true);
			cbxRememberPassword.Checked = state.GetBoolean("RememberPassword", false);
		}

		private string EncryptPassword(string text)
		{
			try
			{
				DESCryptoServiceProvider des = new DESCryptoServiceProvider();

				System.IO.MemoryStream ms = new MemoryStream();

				CryptoStream cs = new CryptoStream(ms, des.CreateEncryptor(byKey, IV), CryptoStreamMode.Write);

				using (StreamWriter sw = new StreamWriter(cs))
				{
					sw.Write(text);
				}

				byte[] data = ms.ToArray();

				string retVal = string.Empty;
				for (int i = 0; i < data.Length; i++)
				{
					retVal += Convert.ToChar(data[i]);
				}

				return retVal;
			}
			catch (Exception ex)
			{
				mParentModule.Host.LogManager.WriteError(this, string.Format("Could not encrypt the password!\n{0}", ex.Message), "DirectoryService");

				return null;
			}
		}

		private string DecryptPassword(string text)
		{
			List<byte> dList = new List<byte>();
			for (int i = 0; i < text.Length; i++)
			{
				dList.Add(Convert.ToByte(text[i]));
			}
			byte[] data = dList.ToArray();
			try
			{
				DESCryptoServiceProvider des = new DESCryptoServiceProvider();

				MemoryStream ms = new MemoryStream();
				ms.Write(data, 0, data.Length);
				ms.Seek(0, SeekOrigin.Begin);

				CryptoStream cs = new CryptoStream(ms, des.CreateDecryptor(byKey, IV), CryptoStreamMode.Read);

				using (StreamReader sr = new StreamReader(cs))
				{
					return sr.ReadToEnd();
				}
			}
			catch (Exception ex)
			{
				mParentModule.Host.LogManager.WriteError(this, string.Format("Could not decrypt the password!\n{0}", ex.Message), "DirectoryService");

				return null;
			}
		}

		#endregion
	}
}
